package me.sealer.ssm.shiro.realm;

import lombok.extern.slf4j.Slf4j;
import me.sealer.ssm.model.Permission;
import me.sealer.ssm.model.Role;
import me.sealer.ssm.model.User;
import me.sealer.ssm.service.RolePermissionService;
import me.sealer.ssm.service.UserRoleService;
import me.sealer.ssm.service.UserService;
import me.sealer.ssm.shiro.authc.EmailToken;
import me.sealer.ssm.shiro.authc.OpenAuth2Token;
import me.sealer.ssm.shiro.authc.PhoneToken;
import me.sealer.ssm.shiro.util.CustomSimpleByteSource;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author sealer
 * @date 2018/05/11.
 */
@Slf4j
public class CustomShiroJdbcRealm extends AuthorizingRealm {
    @Lazy
    @Autowired
    private UserService userService;

    @Lazy
    @Autowired
    private UserRoleService userRoleService;

    @Lazy
    @Autowired
    private RolePermissionService rolePermissionService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }

        String username = (String) getAvailablePrincipal(principals);

        Set<String> roleNames = new HashSet<>(16);
        Set<String> permissions = new HashSet<>(32);

        List<Role> roles = userRoleService.getRolesByUsername(username);
        roles.forEach(role -> {
            // 将每个roleName加到roleNames中
            roleNames.add(role.getName());

            // 将所有roles的permissions全部加到permissions中
            List<Permission> permissionList = rolePermissionService.queryPermissionsByRoleName(role.getName());
            permissionList.forEach(permission -> permissions.add(permission.getPermission()));
        });

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
        info.setStringPermissions(permissions);
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 此处可以继续添加identity之类的token
        if (token instanceof PhoneToken) {
            String credential = token.getCredentials().toString();
            String pass = DigestUtils.md5DigestAsHex((credential).getBytes(StandardCharsets.UTF_8));
            return new SimpleAuthenticationInfo(token.getPrincipal(), pass, getName());
        } else if (token instanceof UsernamePasswordToken) {
            String username = token.getPrincipal().toString();
            User user = userService.queryUserByUsername(username);
            if (user == null) {
                return null;
            }
            String passwordMd5Hex = user.getPassword();
            // salt
            Integer idReal = user.getId();
            // salt不能为Integer, 所以做了个转换变为字符串
            ByteSource idByteSource = new CustomSimpleByteSource("" + idReal);
            return new SimpleAuthenticationInfo(token.getPrincipal(), passwordMd5Hex, idByteSource, getName());
        } else if (token instanceof EmailToken) {
            String email = token.getPrincipal().toString();
            User user = userService.queryUserByEmail(email);
            if (user == null) {
                return null;
            }

            String username = user.getUsername();
            String passwordMd5Hex = user.getPassword();
            // salt
            Integer idReal = user.getId();
            // salt不能为Integer, 所以做了个转换变为字符串
            ByteSource idByteSource = new CustomSimpleByteSource("" + idReal);
            return new SimpleAuthenticationInfo(username, passwordMd5Hex, idByteSource, getName());
        } else if (token instanceof OpenAuth2Token) {
            String username = token.getPrincipal().toString();
            User user = userService.queryUserByUsername(username);
            if (user == null) {
                return null;
            }

            String githubHex = DigestUtils.md5DigestAsHex((token.getCredentials().toString()).getBytes(StandardCharsets.UTF_8));
            return new SimpleAuthenticationInfo(token.getPrincipal(), githubHex, getName());
        }
        return null;
    }

    /**
     * 新增了自定义的Token, 需要在这里注册
     *
     * @param token 待验证是否是支持的Token
     * @return 是否支持该Token
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken
                || token instanceof PhoneToken
                || token instanceof EmailToken
                || token instanceof OpenAuth2Token;
    }

    public static void main(String[] args) {
        String saltString = "2";
        String textPassword = "123456";
        String password = DigestUtils.md5DigestAsHex((saltString + textPassword).getBytes(StandardCharsets.UTF_8));
        System.out.println(password);
    }
}
